#include "ce_core.h"

static void
ce_pool_alloc(ce_pool_t *pool) {
    ce_pool_data_t     *p;
    ce_alloc_t         *alloc;
    size_t              size;

    size = pool->size * pool->n;
    alloc = ce_alloc_create(size);

    alloc->next = pool->alloc;
    pool->alloc = alloc;

    p = (ce_pool_data_t *)alloc->data;
    for (int i = 0; i < pool->n; i++) {
        p->next = pool->free;
        pool->free = p;

        p = (ce_pool_data_t*)((char*)p + pool->size);
    }

    pool->nalloc += pool->n;
    pool->nfree += pool->n;
}

ce_pool_t *
ce_create_pool(size_t data_size, uint32_t n) {
    ce_pool_t          *pool;

    pool = malloc(sizeof(ce_pool_t));

    ce_lock_init(&pool->lock);
    pool->size = data_size;
    pool->n = n;

    pool->alloc = NULL;

    pool->free = NULL;
    pool->nfree = 0;
    pool->nalloc = 0;

    ce_pool_alloc(pool);

    return pool;
}

void
ce_destroy_pool(ce_pool_t *pool) {
    ce_alloc_t         *p;

    ce_lock_lock(&pool->lock);

    p = pool->alloc;
    while (pool->alloc != NULL) {
        p = p->next;
        free(pool->alloc);
        pool->alloc = p;
    }

    ce_lock_unlock(&pool->lock);

    ce_lock_destroy(&pool->lock);

    free(pool);
}

void *
ce_pool_get(ce_pool_t *pool) {
    ce_pool_data_t     *p;

    ce_lock_lock(&pool->lock);

    if (pool->free == NULL) {
        ce_pool_alloc(pool);
    }

    p = pool->free;
    pool->free = p->next;
    pool->nfree--;

    memset(p, 0, pool->size);

    ce_lock_unlock(&pool->lock);

    return p;
}

void
ce_pool_put(ce_pool_t *pool, void *data) {
    ce_pool_data_t     *pool_data = data;

    ce_lock_lock(&pool->lock);

    pool_data->next = pool->free;
    pool->free = pool_data;
    pool->nfree++;

    ce_lock_unlock(&pool->lock);
}
